﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestByWire.Tutorial.Domain;

namespace TestByWire.Tutorial
{
    [TestClass]
    public class ScenarioSpecifications : TestTarget<SalaryManager>
    {
        [TestMethod]
        public void GivenTakesPrecedensOverA()
        {
            Scenario.Is(DefaultBehaviour);

            Given.That<IEmployeStorage>(x => x.RetrieveCurrentSalary("foo")).Returns(new EmployeInformation { Title = "Project Manager" });

            When.Calling.RaiseSalary("foo");

            Then<ISalaryIndex>.Should(x => x.GetSalaryStrategy("Project Manager"));
        }

        [TestMethod]
        public void ScenariosSetUpDefaultBehaviour()
        {
            Scenario.Is(TaxIncrease);

            When.Calling.RaiseSalary("foo");

            Then<IEmployeStorage>.Should(x => x.UpdateSalary(new EmployeInformation { Title = "Business Analyst" }, 200));
        }

        [TestMethod, ExpectedException(typeof(InvalidContextException))]
        public void AStatementsCanOnlyBePartOfAScenario()
        {
            A.CallTo<IEmployeStorage>(x => x.RetrieveCurrentSalary("foo")).Returns(new EmployeInformation());
        }

        [TestMethod, ExpectedException(typeof(InvalidContextException))]
        public void GivenStatementsCanNotBePartOfAScenario()
        {
            Scenario.Is(ScenarioWithGivenStatements);
        }

        [TestMethod]
        public void MustBeAbleToSpecifyFake()
        {
            Scenario.Is(FakeBehavior);

            double newSalery = When.Calling.RaiseSalary("foo");

            Assert.AreEqual(100, newSalery);
        }

        [TestMethod]
        public void MustBeAbleToSpecifyLocalFakeFake()
        {
            Scenario.Is(FakeBehavior);
            Given.Fake<IEmployeStorage>(new MyOtherFakeStorage());

            double newSalery = When.Calling.RaiseSalary("foo");

            Assert.AreEqual(200, newSalery);
        }
        
        private static void ScenarioWithGivenStatements()
        {
            Given.That<IEmployeStorage>(x => x.RetrieveCurrentSalary("foo")).Returns(new EmployeInformation());
        }

        private static void DefaultBehaviour()
        {
            A.CallTo<IEmployeStorage>(x => x.RetrieveCurrentSalary("foo")).Returns(new EmployeInformation { Title = "Business Analyst" });
        }

        private static void FakeBehavior()
        {
            A.Fake<IEmployeStorage>(new MyFakeStorage());
        }

        private static void TaxIncrease()
        {
            A.CallTo<IEmployeStorage>(x => x.RetrieveCurrentSalary("foo")).Returns(new EmployeInformation { Title = "Business Analyst" });
            A.CallTo<ISalaryStrategy>(x => x.CalculateSalaryAdjustment(0)).Returns(200d);
        }
    }
}
